/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-12
 * V4.0
 */
package com.jphenix.share.util;

import com.jphenix.standard.docs.ClassInfo;
import sun.misc.Launcher;

import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

/**
 * 处理类加载器工具
 * @author 刘虻
 * 2008-1-23下午11:46:29
 */
@ClassInfo({"2014-06-12 20:02","处理类加载器工具"})
public class ClassLoaderUtil {

	//添加扫描途径方法
	protected static Method addURLMethod;
	
	static {
		try {
            addURLMethod = 
            	URLClassLoader.class.getDeclaredMethod(
            			"addURL", URL.class);
         } catch (Exception e) {
	        	e.printStackTrace();
         }
         //设置保护
         addURLMethod.setAccessible(true);
	    }
	
	//系统类加载器
	protected static URLClassLoader systemClassLoader = 
	    					(URLClassLoader) getSystemClassLoader();

	//扩展类加载器(比系统类加载器更高一级)
	protected static URLClassLoader extClassLoader = 
			(URLClassLoader) getExtClassLoader();


	/**
	 * 获取系统类加载器
	 * @author 刘虻
	 * 2008-1-27下午03:50:02
	 * @return 系统类加载器
	 */
	public static ClassLoader getSystemClassLoader() {
		return ClassLoader.getSystemClassLoader();
	}

	/**
	 * 获取扩展类加载器
	 * @author 刘虻
	 * 2008-1-27下午03:50:23
	 * @return 扩展类加载器
	 */
	public static ClassLoader getExtClassLoader() {
		return getSystemClassLoader().getParent();
	}

	/**
	 * 获取URL类加载器类路径字符串
	 * 刘虻
	 * 2010-8-8 上午10:20:06
	 * @param cl URL类加载器
	 * @return 类路径字符串
	 */
	public static String getURLClassLoaderPath(ClassLoader cl) {
		//类路径数组序列
		ArrayList<URL[]> pathList = new ArrayList<URL[]>();
		getUrlClassLoaderPathUrls(cl,pathList);
		//构造返回值
		StringBuffer reSbf = new StringBuffer();
		for(URL[] urls:pathList) {
			if(urls==null) {
				continue;
			}
			for(int j=0;j<urls.length;j++) {
				reSbf.append(urls[j].getPath()).append(File.pathSeparator);
			}
		}
		return reSbf.toString();
	}
	
	/**
	 * 获取类加载中的类路径序列
	 * 刘虻
	 * 2010-8-8 上午10:23:19
	 * @param cl URL类加载器
	 * @param pathList 类路径序列
	 */
	public static void getUrlClassLoaderPath(ClassLoader cl,ArrayList<String> pathList) {
		//类路径URL数组序列
		ArrayList<URL[]> pList = new ArrayList<URL[]>();
		getUrlClassLoaderPathUrls(cl,pList); //获取信息
		for(URL[] urls:pList) {
			if(urls==null) {
				continue;
			}
			for(int j=0;j<urls.length;j++) {
				pathList.add(urls[j].getPath());
			}
		}
	}

	
	/**
	 * 将URL类加载器以及其父类加载器所有的url数组放入序列中(递归函数)
	 * 刘虻
	 * 2010-8-8 上午10:23:19
	 * @param cl URL类加载器
	 * @param pathList 类路径数组序列
	 */
	public static void getUrlClassLoaderPathUrls(ClassLoader cl,ArrayList<URL[]> pathList) {
		if(cl==null) {
			return;
		}
		if(cl instanceof URLClassLoader) {
			pathList.add(((URLClassLoader) cl).getURLs());
			getUrlClassLoaderPathUrls(cl.getParent(),pathList);
		}else {
			return;
		}
	}

	/**
	 * 获取启动类路经数组
	 * @author 刘虻
	 * 2008-1-27下午03:53:18
	 * @return 启动类路经数组
	 */
	public static URL[] getBootstrapURLs() {
		return Launcher.getBootstrapClassPath().getURLs();
	}


	/**
	 * 获取系统类路经数组
	 * @author 刘虻
	 * 2008-1-27下午03:54:04
	 * @return 系统类路经数组
	 */
	public static URL[] getSystemURLs() {
		return systemClassLoader.getURLs();
	}


	/**
	 * 获取扩展类路经数组
	 * @author 刘虻
	 * 2008-1-27下午03:54:38
	 * @return 扩展类路经数组
	 */
	public static URL[] getExtURLs() {
		return extClassLoader.getURLs();
	}


	/**
	 * 打印类路经
	 * @author 刘虻
	 * 2008-1-27下午03:56:55
	 * @param ps 输出流
	 * @param classPath 类路经数组
	 */
	protected static void list(PrintStream ps, URL[] classPath) {
		for (int i=0; i<classPath.length; i++) {
		    ps.println(classPath[i]);
		}
   }

	/**
	 * 打印出启动类路经
	 * @author 刘虻
	 * 2008-1-27下午03:57:42
	 */
    public static void listBootstrapClassPath() {
        listBootstrapClassPath(System.out);
    }

    /**
     * 用指定输出流打印启动类路经
     * @author 刘虻
     * 2008-1-27下午03:57:58
     * @param ps 指定输出流
     */
    public static void listBootstrapClassPath(PrintStream ps) {
        ps.println("BootstrapClassPath:");
        list(ps, getBootstrapClassPath());
    }

    /**
     * 打印出系统类路经
     * @author 刘虻
     * 2008-1-27下午03:58:33
     */
	public static void listSystemClassPath() {
	    listSystemClassPath(System.out);
	}

	/**
	 * 用指定输出流打印系统类路经
	 * @author 刘虻
	 * 2008-1-27下午03:58:47
	 * @param ps 指定输出流
	 */
    public static void listSystemClassPath(PrintStream ps) {
        ps.println("SystemClassPath:");
        list(ps, getSystemClassPath());
    }

    /**
     * 获取系统类路径字符串
     * 刘虻
     * 2010-4-30 下午01:33:08
     * @return 系统类路径字符串
     */
    public static String getSystemClassPathString() {
    	//获取类路径url
    	URL[] urls = getSystemClassPath();
    	//构建返回值
    	StringBuffer reSbf = new StringBuffer();
    	if(urls!=null) {
    		for(int i=0;i<urls.length;i++) {
    			reSbf.append(urls[i].getPath()).append(File.pathSeparator);
    		}
    	}
    	return reSbf.toString();
    }
    
    /**
     * 打印扩展类路经
     * @author 刘虻
     * 2008-1-27下午03:59:08
     */
    public static void listExtClassPath() {
        listExtClassPath(System.out);
    }

    /**
     * 用指定输出流输出扩展类路经
     * @author 刘虻
     * 2008-1-27下午03:59:22
     * @param ps 指定输出流
     */
    public static void listExtClassPath(PrintStream ps) {
        ps.println("ExtClassPath:");
        list(ps, getExtClassPath());
    }

    /**
     * 获取启动类路经数组
     * @author 刘虻
     * 2008-1-27下午03:59:42
     * @return 启动类路经数组
     */
    public static URL[] getBootstrapClassPath() {
        return getBootstrapURLs();
    }

    /**
     * 获取指定系统类路经数组
     * @author 刘虻
     * 2008-1-27下午03:59:59
     * @return 指定系统类路经数组
     */
    public static URL[] getSystemClassPath() {
        return getSystemURLs();
    }

    /**
     * 获取扩展类路经数组
     * @author 刘虻
     * 2008-1-27下午04:00:15
     * @return 扩展类路经数组
     */
    public static URL[] getExtClassPath() {
        return getExtURLs();
    }

    /**
     * 加载指定类路经到系统类加载器中
     * @author 刘虻
     * 2008-1-27下午04:00:27
     * @param url 指定类路经
     */
    public static void addURL2SystemClassLoader(URL url) {
        try {
            addURLMethod.invoke(systemClassLoader, url);
        } catch (Exception e) {
        	e.printStackTrace();
        }
    }

    /**
     * 加载指定类路经到扩展类加载器中
     * @author 刘虻
     * 2008-1-27下午04:01:02
     * @param url 指定类路经
     */
    public static void addURL2ExtClassLoader(URL url) {
        try {
            addURLMethod.invoke(extClassLoader, url);
        } catch (Exception e) {
        	e.printStackTrace();
        }
    }

    /**
     * 添加类路经到系统类加载器中
     * @author 刘虻
     * 2008-1-27下午04:01:48
     * @param path 类路经
     */
    public static void addClassPath(String path) {
        addClassPath(new File(path));
    }

    /**
     * 添加类路经到扩展类加载器中
     * @author 刘虻
     * 2008-1-27下午04:02:09
     * @param path 类路经
     */
    public static void addExtClassPath(String path) {
        addExtClassPath(new File(path));
    }

    /**
     * 添加类类路经到系统类加载器中
     * @author 刘虻
     * 2008-1-27下午04:02:45
     * @param dirOrJar 路经文件对象
     */
    @SuppressWarnings("deprecation")
    public static void addClassPath(File dirOrJar) {
        try {
            addURL2SystemClassLoader(dirOrJar.toURL());
        } catch (MalformedURLException e) {
        }
    }

    /**
     * 添加指定类路经到扩展类加载器中
     * @author 刘虻
     * 2008-1-27下午04:03:19
     * @param dirOrJar 路经文件对象
     */
    @SuppressWarnings("deprecation")
    public static void addExtClassPath(File dirOrJar) {
        try {
            addURL2ExtClassLoader(dirOrJar.toURL());
        } catch (MalformedURLException e) {
        	e.printStackTrace();
        }
    }
    
    
    /**
     * 向当前类加载器中放入新的类路径
     * 刘虻
     * 2010-8-8 上午10:45:43
     * @param path 类路径
     */
    @SuppressWarnings("deprecation")
    public static void addUrl(String path) {
    	try {
    		addUrl((new File(path)).toURL());
    	}catch(Exception e) {
    		e.printStackTrace();
    	}
    }
    
    /**
     * 向当前类加载器中放入新的类路径
     * 刘虻
     * 2010-8-8 上午11:05:19
     * @param url 类路径
     */
    public static void addUrl(URL url) {
    	if(!(ClassLoaderUtil.class.getClassLoader() instanceof URLClassLoader)) {
    		return;
    	}
    	try {
	    	//获取方法
			Method addUrls = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
			addUrls.setAccessible(true); //设置保护
			addUrls.invoke(ClassLoaderUtil.class.getClassLoader(), url);
    	}catch (Exception e) {
    		e.printStackTrace();
    	}
    }
}
